package cc.comac.saic.hkhy.jsrj.gj.inttools.service.impl;

import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import org.gitlab4j.api.GitLabApiException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import cc.comac.saic.hkhy.jsrj.gj.inttools.constant.FileType;
import cc.comac.saic.hkhy.jsrj.gj.inttools.dao.FileInfoDao;
import cc.comac.saic.hkhy.jsrj.gj.inttools.dao.FileVersionInfoDao;
import cc.comac.saic.hkhy.jsrj.gj.inttools.dao.ProjectInfoDao;
import cc.comac.saic.hkhy.jsrj.gj.inttools.entity.FileInfo;
import cc.comac.saic.hkhy.jsrj.gj.inttools.entity.FileVersionInfo;
import cc.comac.saic.hkhy.jsrj.gj.inttools.entity.ProjectInfo;
import cc.comac.saic.hkhy.jsrj.gj.inttools.gitlab.VersionManegeClient;
import cc.comac.saic.hkhy.jsrj.gj.inttools.pojo.vo.FileInfoShowVo;
import cc.comac.saic.hkhy.jsrj.gj.inttools.pojo.vo.FileTypeStatVo;
import cc.comac.saic.hkhy.jsrj.gj.inttools.pojo.vo.FileVersionShowVo;
import cc.comac.saic.hkhy.jsrj.gj.inttools.service.FileInfoService;
import jakarta.servlet.http.Part;

/**
 * 文件信息(FileInfo)表服务实现类
 *
 * @author makejava
 * @since 2025-07-02 18:26:30
 */
@Service
public class FileInfoServiceImpl implements FileInfoService {
    @Autowired
    private ProjectInfoDao projectInfoDao;
    @Autowired
    private FileInfoDao fileInfoDao;
    @Autowired
    private FileVersionInfoDao fileVersionInfoDao;
    @Autowired
    private VersionManegeClient versionManegeClient;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public FileInfo queryById(Long id) {
        return this.fileInfoDao.queryById(id);
    }

    @Override
    public FileInfoShowVo queryVersionByDataKey(String key) {
        FileInfo fileInfo = fileInfoDao.queryByKey(key);
        List<FileVersionInfo> fileVersionInfos = fileVersionInfoDao.queryByFileId(fileInfo.getId());

        FileInfoShowVo fileInfoShowVo = new FileInfoShowVo();
        fileInfoShowVo.setId(fileInfo.getId());
        fileInfoShowVo.setDataKey(key);
        fileInfoShowVo.setProjId(fileInfo.getProjId());
        fileInfoShowVo.setPath(fileInfo.getFilePath());
        List<FileVersionShowVo> fileVersionShowVos = fileVersionInfos.stream()
            .map(fileVersionInfo -> new FileVersionShowVo(fileVersionInfo.getHash(), fileVersionInfo.getCreateTime()))
            .collect(Collectors.toList());
        fileInfoShowVo.setVersions(fileVersionShowVos);

        return fileInfoShowVo;
    }

    /**
     * 分页查询
     *
     * @param fileInfo 筛选条件
     * @return 查询结果
     */
    @Override
    public List<FileInfo> queryByCondition(FileInfo fileInfo) {
        return this.fileInfoDao.queryByCondition(fileInfo);
    }

    /**
     * 新增数据
     *
     * @param fileInfo 实例对象
     * @return 实例对象
     */
    @Override
    public FileInfo insert(FileInfo fileInfo) {
        this.fileInfoDao.insert(fileInfo);
        return fileInfo;
    }

    /**
     * 修改数据
     *
     * @param fileInfo 实例对象
     * @return 实例对象
     */
    @Override
    public FileInfo update(FileInfo fileInfo) {
        this.fileInfoDao.update(fileInfo);
        return this.queryById(fileInfo.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Long id) {
        return this.fileInfoDao.deleteById(id) > 0;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public List<FileInfoShowVo> upload(String projKey, FileType fileType, Collection<Part> fileParts) {
        try {
            String commitHash = versionManegeClient.uploadFiles(projKey, fileType, fileParts);
            ProjectInfo projectInfo = projectInfoDao.queryByKey(projKey);
            return fileParts.stream()
                .filter(part -> StringUtils.hasText(part.getSubmittedFileName()))
                .map(part -> {
                    FileInfoShowVo fileInfoShowVo = new FileInfoShowVo();
                    String originalFilePath = part.getSubmittedFileName();
                    FileInfo fileInfo = fileInfoDao.queryByProjectIdAndFilePath(projectInfo.getId(), fileType.getCode(), originalFilePath);

                    if (Objects.isNull(fileInfo)) {
                        fileInfo = new FileInfo();
                        fileInfo.setFileKey(originalFilePath);
                        fileInfo.setFilePath(originalFilePath);
                        fileInfo.setFileType(fileType.getCode());
                        fileInfo.setProjId(projectInfo.getId());
                        fileInfoDao.insert(fileInfo);
                    }

                    FileVersionInfo fileVersionInfo = fileVersionInfoDao.queryLatestByFileId(fileInfo.getId());
                    String version = Optional.ofNullable(fileVersionInfo)
                        .map(FileVersionInfo::getVersion)
                        .map(ver -> String.valueOf(Integer.parseInt(ver) + 1))
                        .orElse("1");

                    fileVersionInfo = new FileVersionInfo();
                    fileVersionInfo.setFileInfoId(fileInfo.getId());
                    fileVersionInfo.setVersion(version);
                    fileVersionInfo.setHash(commitHash);
                    fileVersionInfoDao.insert(fileVersionInfo);

                    fileInfoShowVo.setId(fileInfo.getId());
                    fileInfoShowVo.setDataKey(fileInfo.getFileKey());
                    fileInfoShowVo.setPath(originalFilePath);
                    fileInfoShowVo.setVersions(Collections.singletonList(new FileVersionShowVo(commitHash, new Date())));

                    return fileInfoShowVo;
                }).collect(Collectors.toList());
        } catch (GitLabApiException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public byte[] download(String projKey, String fileType, String filePath, String versionHash) {
        try {
            ProjectInfo projectInfo = projectInfoDao.queryByKey(projKey);
            FileInfo fileInfo = fileInfoDao.queryByProjectIdAndFilePath(projectInfo.getId(), fileType, filePath);

            // 如果versionHash为空，则查询最新版本
            if (!StringUtils.hasText(versionHash)) {
                versionHash = Optional.ofNullable(fileVersionInfoDao.queryLatestByFileId(fileInfo.getId())).map(FileVersionInfo::getHash).orElseThrow();
            }

            return versionManegeClient.getFileBytes(projKey, Objects.requireNonNull(FileType.getFileTypeByCode(fileType)), filePath, versionHash);
        } catch (GitLabApiException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<FileTypeStatVo> getFileTypeStatsByProjectId(Long projId) {
        List<Map<String, Object>> rawStats = fileInfoDao.countFileTypeByProjectId(projId);
        if (rawStats == null) return Collections.emptyList();
        return rawStats.stream()
            .map(map -> new FileTypeStatVo(
                String.valueOf(map.get("name")),
                ((Number) map.get("value")).intValue()
            ))
            .collect(java.util.stream.Collectors.toList());
    }
}
